package com.king.nio;

import java.io.*;
import java.lang.reflect.Field;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;

/**
 * @author taomk
 * @version 1.0
 * @since 15-1-25 下午12:03
 */
public class BufferTest {

	public static void main(String [] args) throws Exception {
		testBuffer();
		testMark();
		testDuplicate();
		testSlice();
		testReadOnlyBuffer();
		testMappedBuffer();
		testGathering();
		testScattering();
		testDirectBuffer();
		monitorDirectBuffer();
	}

	public static void testBuffer() {
		// 15个字节大小的缓冲区
		ByteBuffer b = ByteBuffer.allocate(15);
		System.out.println("limit=" + b.limit() + ", capacity=" + b.capacity() + ", position=" + b.position());
		// 存入10个字节数据
		for (int i = 0; i < 10; i++) {
			b.put((byte)i);
		}
		System.out.println("limit=" + b.limit() + ", capacity=" + b.capacity() + ", position=" + b.position());
		// 重置position
		b.flip();
		System.out.println("limit=" + b.limit() + ", capacity=" + b.capacity() + ", position=" + b.position());
		// 读取5个字节数据
		for (int i = 0; i < 5; i++) {
			System.out.print(b.get());
		}
		System.out.println();
		System.out.println("limit=" + b.limit() + ", capacity=" + b.capacity() + ", position=" + b.position());
		b.flip();
		System.out.println("limit=" + b.limit() + ", capacity=" + b.capacity() + ", position=" + b.position());
	}

	/**
	 * 缓冲区：标志位
	 */
	public static void testMark() {
		// 15个字节大小的缓冲区
		ByteBuffer b = ByteBuffer.allocate(15);
		// 存入10个字节数据
		for (int i = 0; i < 10; i++) {
			b.put((byte)i);
		}
		b.flip();
		for (int i = 0; i < b.limit(); i++) {
			System.out.print(b.get());
			if (i == 4) {
				// 在第4个位置做mark
				b.mark();
				System.out.print("{mark at " + i + "}");
			}
		}
		// 回到mark的位置，并处理后续数据
		b.reset();
		System.out.println("\nreset to mark");
		while (b.hasRemaining()) {
			System.out.print(b.get());
		}
	}

	/**
	 * 缓冲区：复制
	 */
	public static void testDuplicate() {
		// 15个字节大小的缓冲区
		ByteBuffer b = ByteBuffer.allocate(15);
		// 存入10个字节数据
		for (int i = 0; i < 10; i++) {
			b.put((byte)i);
		}
		// 复制当前缓冲区
		ByteBuffer c = b.duplicate();
		System.out.println("After b.duplicate()");
		System.out.println(b);
		System.out.println(c);
		// 重置缓冲区c
		c.flip();
		System.out.println("After c.flip()");
		System.out.println(b);
		System.out.println(c);
		// 向缓冲区c存入数据
		c.put((byte)100);
		System.out.println("After c.put((byte)100)");
		System.out.println("b.get(0)=" + b.get(0));
		System.out.println("c.get(0)=" + c.get(0));
	}

	/**
	 * 缓冲区：分片
	 */
	public static void testSlice() {
		// 15个字节大小的缓冲区
		ByteBuffer b = ByteBuffer.allocate(15);
		// 存入10个字节数据
		for (int i = 0; i < 10; i++) {
			b.put((byte)i);
		}
		b.position(2);
		b.limit(6);
		// 生成子缓冲区
		ByteBuffer subBuffer = b.slice();
		for (int i = 0; i < subBuffer.capacity(); i++) {
			byte bb = subBuffer.get(i);
			bb *= 10;
			subBuffer.put(i, bb);
		}
		// 重置父缓冲区，并查看父缓冲区的数据
		b.position(0);
		b.limit(b.capacity());
		while (b.hasRemaining()) {
			System.out.print(b.get());
		}
	}

	/**
	 * 缓冲区：只读
	 */
	public static void testReadOnlyBuffer() {
		// 15个字节大小的缓冲区
		ByteBuffer b = ByteBuffer.allocate(15);
		// 存入10个字节数据
		for (int i = 0; i < 10; i++) {
			b.put((byte)i);
		}
		// 创建只读缓冲区
		ByteBuffer readOnly = b.asReadOnlyBuffer();
		readOnly.flip();
		while (readOnly.hasRemaining()) {
			System.out.println(readOnly.get());
		}
		System.out.println();
		// 修改原始缓冲区数据
		b.put(2, (byte)20);
		// readOnly.put(2, (byte)20); 会抛出ReadOnlyBufferException
		readOnly.flip();
		// 新的改动，在只读缓冲区内可见
		while (readOnly.hasRemaining()) {
			System.out.println(readOnly.get());
		}
	}

	/**
	 * 缓冲区：文件映射到内存
	 */
	public static void testMappedBuffer() throws IOException {
		RandomAccessFile raf = new RandomAccessFile("/home/taomk/abc.txt", "rw");
		FileChannel fc = raf.getChannel();

		// 将文件映射到内存
		MappedByteBuffer mbb = fc.map(FileChannel.MapMode.READ_WRITE, 0, raf.length());
		while (mbb.hasRemaining()) {
			System.out.print((char)mbb.get());
		}
		mbb.put(0, (byte) 98);
		raf.close();
	}

	/**
	 * 缓冲区：聚集
	 */
	public static void testGathering() throws Exception {
		ByteBuffer bookBuf = ByteBuffer.wrap("java性能优化技巧".getBytes("UTF-8"));
		ByteBuffer autBuf = ByteBuffer.wrap("葛一鸣".getBytes("UTF-8"));
		ByteBuffer [] bufs = new ByteBuffer[]{bookBuf, autBuf};
		File file = new File("");
		if (!file.exists()) {
			file.createNewFile();
		}
		FileOutputStream fos = new FileOutputStream(file);
		FileChannel fc = fos.getChannel();
		fc.write(bufs);
		fos.close();
	}

	/**
	 * 缓冲区：散射
	 */
	public static void testScattering() throws Exception {
		ByteBuffer bookBuf = ByteBuffer.allocate(16);
		ByteBuffer autBuf = ByteBuffer.allocate(6);
		ByteBuffer [] bufs = new ByteBuffer[]{bookBuf, autBuf};
		File file = new File("");
		FileInputStream fis = new FileInputStream(file);
		FileChannel fc = fis.getChannel();
		fc.read(bufs);
		String bookName = new String(bufs[0].array(), "UTF-8");
		String authName = new String(bufs[1].array(), "UTF-8");
		System.out.println(bookName + ", " + authName);
	}

	/**
	 * 缓冲区：直接内存
	 */
	public static void testDirectBuffer() {
		// 分配DirectBuffer
		ByteBuffer b = ByteBuffer.allocateDirect(500);
		for (int i = 0; i < 100000; i++) {
			for (int j = 0; j < 99; j++) {
				b.putInt(j);
			}
			b.flip();
			for (int j = 0; j < 99; j++) {
				b.getInt();
			}
			b.clear();
		}
	}

	/**
	 * 缓冲区：直接内存监控
	 */
	public static void monitorDirectBuffer() throws Exception {
		Class c = Class.forName("java.nio.Bits");

		// 通过反射取得私有属性
		Field maxMemory = c.getDeclaredField("maxMemory");
		maxMemory.setAccessible(true);

		Field reservedMemory = c.getDeclaredField("reservedMemory");
		reservedMemory.setAccessible(true);

		synchronized (c) {
			// 总大小
			Long maxMemoryVal = (Long) maxMemory.get(null);
			// 剩余大小
			Long reservedMemoryVal = (Long) reservedMemory.get(null);

			System.out.println("maxMemoryVal: " + maxMemoryVal);
			System.out.println("reservedMemoryVal: " + reservedMemoryVal);
		}
	}
}
